package com.xuyuan.json.jackson.custom;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.type.TypeFactory;

import java.io.IOException;

public class ObjAndArrayDeserializer extends StdDeserializer<Object> implements ContextualDeserializer {

    private Class<?> clazz;

    private Class<?> internal;

    /**
     * <p>对于泛型对象需要知道实际的JavaType不然无法处理。
     * <p>jackson 反序列化执行的时候需要知道当前的字段需要反序列化到哪个对象，需要获取对应的JavaType，如果没有泛型可以不获取JavaType。
     * <p>如果是Person的JavaType TypeFactory.defaultInstance().constructType(Person.class);可以不获取JavaType，直接使用readValue(String content, Class<T> valueType)
     * <p>这里没有办法直接使用readValues(JsonParser p, TypeReference<T> valueTypeRef)实现。因为无法直接获取泛型对应的真实对象。
     */
    private JavaType javaType;

    public ObjAndArrayDeserializer(Class<?> clazz, Class<?> internal) {
        super(clazz);
        this.clazz = clazz;
        this.internal = internal;
        // 获取JavaType的工厂对象以获取JavaType
        TypeFactory typeFactory = TypeFactory.defaultInstance();
        // 获取Bodys<Person>对应的JavaType
        this.javaType = typeFactory.constructParametricType(this.clazz, this.internal);
        // 如果是List<Person>对应的JavaType，TypeFactory.defaultInstance().constructParametricType(List.class,Person.class);
        // 如果是Person的JavaType TypeFactory.defaultInstance().constructType(Person.class);
    }

    public ObjAndArrayDeserializer() {
        super(Object.class);
    }

    @Override
    public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        JsonToken currentToken = p.getCurrentToken();
        if (currentToken == JsonToken.START_ARRAY) {
            p.nextToken();
            Object o = p.getCodec().readValue(p, this.javaType);
            p.nextToken();
            return o;
        } else {
            return null;
        }
    }

    /*获取Field的相关信息，以获取对应的JavaType,缓存了反序列化器，需要重启才会再走*/
    @Override
    public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException {
        ObjAndArrayConverter converter = property.getAnnotation(ObjAndArrayConverter.class);
        this.clazz = converter.clazz();
        this.internal = converter.internal();
        return new ObjAndArrayDeserializer(converter.clazz(), converter.internal());
    }
}
